package cn.ppool.xmlmapper.builder.parse.parsetest;

import cn.ppool.xmlmapper.exctption.CharSymbolNotDefineException;
import cn.ppool.xmlmapper.exctption.OperatorNotDefineException;
import lombok.Getter;
import lombok.extern.log4j.Log4j2;

import java.util.Arrays;
import java.util.List;

/**
 * 解析test运行变量类
 */
@Log4j2
public class TestStringRunTime {

    public final static List<String> BaseOperatorSymbolDefine = Arrays.asList(">", "=", "<", "&", "|", "+", "-", "*", "/", "!");          // 基本运算符定义
    public final static List<String> CharSymbolDefine = Arrays.asList(      // 字符定义
            "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
            "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
            "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
            "_", "$", "{", "}");
    //
    public final static List<String> OperatorDefine = Arrays.asList(">", "=", "==", "<", ">=", "<=", "&", "&&", "|", "||", "+", "-", "*", "/", "!=");   // 运算符定义
    public final static List<String> AutoOperatorDefine = Arrays.asList("!empty");
    public final static List<String> CharBracketsDefine = Arrays.asList("(", ")");
    public final static List<String> StringTypeSymbol = Arrays.asList("'", "\"");
    public final static String TransferSymbol = "\\";


    @Getter
    private int brackets;            // 左右括号数量计算
    private int index;               // test指针
    private final String test;             // test表达式

    @Getter
    public class TestWordVO {
        public TestWordVO(TYPE_ENUM type, String word) {
            this.type = type;
            this.word = word;
        }

        private TYPE_ENUM type;
        private String word;
    }

    /**
     * 构造函数
     *
     * @param test 布尔表达式
     */
    public TestStringRunTime(final String test) {
        this.brackets = 0;
        this.test = test.concat(" ");
        this.index = -1;
        indexMoveNext();
    }

    public boolean isEndIndex() {
        return (this.index == this.test.length() - 1);
    }

    /**
     * 指针移动一位
     */
    public void indexMoveNext() {
        this.index++;
        String moStr = getTestOnIndex();
        if ("(".equals(moStr)) brackets++;
        if (")".equals(moStr)) brackets--;
    }

    /**
     * 指针回退一位
     */
    public void indexMoveBack() {
        String moStr = getTestOnIndex();
        if ("(".equals(moStr)) brackets--;
        if (")".equals(moStr)) brackets++;
        this.index--;
    }

    /**
     * 获得当前字符
     */
    public String getTestOnIndex() {
        return String.valueOf(test.charAt(this.index));
    }

    public String getTestOnNextIndex() {
        return String.valueOf(test.charAt(this.index + 1));
    }


    private String getOperator() {
        StringBuilder ret = new StringBuilder();
        while (true) {
            String currChar = getTestOnIndex();
            if ((" ".equals(currChar))) {
                break;
            } else if (ret.length() > 0 && currChar.equals("!")) {
                indexMoveBack();        // 回退一个
                break;
            } else if (BaseOperatorSymbolDefine.contains(currChar)) {    // 运算符
                ret.append(currChar);
            } else if (CharSymbolDefine.contains(currChar) || CharBracketsDefine.contains(currChar) || StringTypeSymbol.contains(currChar)) {        // 普通字符 或 括号 或 字符串符号
                indexMoveBack();        // 回退一个
                break;
            } else {
                throw new OperatorNotDefineException("无效的运算符：" + currChar);
            }
            if (isEndIndex()) break;
            indexMoveNext();
        }
        if (!OperatorDefine.contains(ret.toString())) throw new OperatorNotDefineException("无效的运算符：" + ret);
        return ret.toString();
    }

    private String getWord() {
        StringBuilder ret = new StringBuilder();
        String lastSymbol = "";
        String intoStringSymbol = "";
        while (true) {
            String currChar = getTestOnIndex();
            if (ret.length() == 0 && StringTypeSymbol.contains(currChar)) {
                intoStringSymbol = currChar;
            } else if ((" ".equals(currChar) || StringTypeSymbol.contains(currChar)) && !TransferSymbol.equals(lastSymbol)) {
                break;
            } else if (BaseOperatorSymbolDefine.contains(currChar) || CharBracketsDefine.contains(currChar)) {    // 运算符 和 括号
                indexMoveBack();    // 回退一个
                break;
            } else if (CharSymbolDefine.contains(currChar) || StringTypeSymbol.contains(currChar)) {        // 普通字符
                ret.append(currChar);
            } else {
                throw new CharSymbolNotDefineException("无效的字符：" + currChar);
            }
            if (isEndIndex()) break;
            indexMoveNext();
            lastSymbol = currChar;
        }
        if (intoStringSymbol.length() > 0) {
            ret.insert(0, intoStringSymbol).append(intoStringSymbol);
        }
        return ret.toString();
    }


    public TestWordVO getNextWord() {
        String word = null;
        TYPE_ENUM type = null;
        while (true) {
            String currSymbol = getTestOnIndex();
            if (currSymbol.equals(" ")) {
                if (!isEndIndex()) indexMoveNext();
            } else if (currSymbol.equals("(")) {
                type = TYPE_ENUM.brackets;
                word = currSymbol;
                break;
            } else if (currSymbol.equals(")")) {
                type = TYPE_ENUM.brackets;
                word = currSymbol;
                break;
            } else if (StringTypeSymbol.contains(currSymbol)) {
                type = TYPE_ENUM.string;
                word = getWord();
                break;
            } else if (BaseOperatorSymbolDefine.contains(currSymbol)) {     // 运算符 或 !empty
                if (isEndIndex()) break;
                String nextSymbol = getTestOnNextIndex();
                if (currSymbol.equals("!") && CharSymbolDefine.contains(nextSymbol)) {         // !empty
                    type = TYPE_ENUM.autoFillOperator;
                    if (!isEndIndex()) indexMoveNext();
                    word = currSymbol.concat(getWord());
                } else {                                                                        // 运算符
                    type = TYPE_ENUM.operate;
                    word = getOperator();
                }
                break;
            } else if (CharSymbolDefine.contains(currSymbol)) {             // 字符
                type = TYPE_ENUM.word;
                word = getWord();
                break;
            }
            if (isEndIndex()) break;
        }
        if (!isEndIndex()) indexMoveNext();
        return new TestWordVO(type, word);
    }


}
